package com.ruoyi.system.service.impl;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ImageWatermarkUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.system.domain.SysHoliday;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysHolidayMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysAttendanceMapper;
import com.ruoyi.system.domain.SysAttendance;
import com.ruoyi.system.service.ISysAttendanceService;
import org.springframework.web.multipart.MultipartFile;

/**
 * 打卡记录Service业务层处理
 *
 * @author ruoyi
 * @date 2025-09-24
 */
@Service
public class SysAttendanceServiceImpl implements ISysAttendanceService {


    private static final List<Map<String, Object>> OFFICE_TIME_RANGES;
    private static final List<Map<String, Object>> FIELD_TIME_RANGES;

    // 静态块初始化时间范围数据
    static {
        // 初始化办公室考勤时间范围
        OFFICE_TIME_RANGES = new ArrayList<>();
        Map<String, Object> officeTime1 = new HashMap<>();
        officeTime1.put("timeRange", "08:00-08:30");
        officeTime1.put("startTime", "08:00");
        officeTime1.put("endTime", "08:30");
        officeTime1.put("timeType", "上午");
        officeTime1.put("isCurrent", false);

        Map<String, Object> officeTime2 = new HashMap<>();
        officeTime2.put("timeRange", "12:00-14:00");
        officeTime2.put("startTime", "12:00");
        officeTime2.put("endTime", "14:00");
        officeTime2.put("timeType", "中午");
        officeTime2.put("isCurrent", false);

        Map<String, Object> officeTime3 = new HashMap<>();
        officeTime3.put("timeRange", "17:30-19:00");
        officeTime3.put("startTime", "17:30");
        officeTime3.put("endTime", "23:00");
        officeTime3.put("timeType", "下午");
        officeTime3.put("isCurrent", false);

        OFFICE_TIME_RANGES.add(officeTime1);
        OFFICE_TIME_RANGES.add(officeTime2);
        OFFICE_TIME_RANGES.add(officeTime3);

        // 初始化外勤考勤时间范围
        FIELD_TIME_RANGES = new ArrayList<>();
        Map<String, Object> fieldTime1 = new HashMap<>();
        fieldTime1.put("timeRange", "09:00-10:00");
        fieldTime1.put("startTime", "09:00");
        fieldTime1.put("endTime", "10:00");
        fieldTime1.put("timeType", "上午");
        fieldTime1.put("isCurrent", false);

        Map<String, Object> fieldTime2 = new HashMap<>();
        fieldTime2.put("timeRange", "15:00-16:00");
        fieldTime2.put("startTime", "15:00");
        fieldTime2.put("endTime", "16:00");
        fieldTime2.put("timeType", "下午");
        fieldTime2.put("isCurrent", false);

        FIELD_TIME_RANGES.add(fieldTime1);
        FIELD_TIME_RANGES.add(fieldTime2);
    }

    @Autowired
    private SysAttendanceMapper sysAttendanceMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SysHolidayMapper sysHolidayMapper;

    @Value("${base.url}")
    private String baseUrl;

    /**
     * 查询打卡记录
     *
     * @param attendanceId 打卡记录主键
     * @return 打卡记录
     */
    @Override
    public SysAttendance selectSysAttendanceByAttendanceId(Long attendanceId) {
        return sysAttendanceMapper.selectSysAttendanceByAttendanceId(attendanceId);
    }

    /**
     * 查询打卡记录列表
     *
     * @param sysAttendance 打卡记录
     * @return 打卡记录
     */
    @Override
    public List<SysAttendance> selectSysAttendanceList(SysAttendance sysAttendance) {
        List<SysAttendance> sysAttendanceList = sysAttendanceMapper.selectSysAttendanceList(sysAttendance);


        List<SysUser> sysUsers = sysUserMapper.selectUserList(null);
        Map<Long, String> userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName));

        sysAttendanceList.forEach(a -> {
            if (a.getUserId() != null) {
                a.setNickName(userMap.getOrDefault(a.getUserId(), ""));
            }
        });


        return sysAttendanceList;
    }


    /**
     * 修改打卡记录
     *
     * @param sysAttendance 打卡记录
     * @return 结果
     */
    @Override
    public int updateSysAttendance(SysAttendance sysAttendance) {
        sysAttendance.setUpdateTime(DateUtils.getNowDate());
        return sysAttendanceMapper.updateSysAttendance(sysAttendance);
    }

    /**
     * 批量删除打卡记录
     *
     * @param attendanceIds 需要删除的打卡记录主键
     * @return 结果
     */
    @Override
    public int deleteSysAttendanceByAttendanceIds(Long[] attendanceIds) {
        return sysAttendanceMapper.deleteSysAttendanceByAttendanceIds(attendanceIds);
    }

    /**
     * 删除打卡记录信息
     *
     * @param attendanceId 打卡记录主键
     * @return 结果
     */
    @Override
    public int deleteSysAttendanceByAttendanceId(Long attendanceId) {
        return sysAttendanceMapper.deleteSysAttendanceByAttendanceId(attendanceId);
    }


    @Override
    public AjaxResult checkSwitch() {

        Map<String, Object> result = new HashMap<>();

        Date currentDate = DateUtil.beginOfDay(DateUtil.date());

        SysAttendance sysAttendance = new SysAttendance();
        sysAttendance.setAttendanceDate(currentDate);
        sysAttendance.setUserId(SecurityUtils.getUserId());

        List<SysAttendance> sysAttendanceList = sysAttendanceMapper.selectSysAttendanceList(sysAttendance);

        if (CollectionUtils.isNotEmpty(sysAttendanceList)) {
            result.put("status", 0);
        } else {
            result.put("status", 0);
        }

        return AjaxResult.success(result);
    }

    /**
     * 校验动态传入的考勤时间是否在有效时段内
     *
     * @param attendanceTime 动态获取的考勤时间（非固定）
     * @param attendanceType 考勤类型（office/field）
     * @return 是否有效
     */
    public boolean validateAttendanceTime(Date attendanceTime, String attendanceType) {
        // 参数校验
        if (attendanceTime == null || attendanceType == null) {
            return false;
        }

        // 将Date转换为LocalTime，仅提取时分秒信息（忽略具体日期）
        LocalTime checkTime = attendanceTime.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalTime();

        if ("field".equals(attendanceType)) {
            return isTimeInRange(checkTime, LocalTime.of(9, 0), LocalTime.of(10, 0)) ||
                    isTimeInRange(checkTime, LocalTime.of(15, 0), LocalTime.of(16, 0));
        } else if ("office".equals(attendanceType)) {
            return isTimeInRange(checkTime, LocalTime.of(8, 0), LocalTime.of(8, 30)) ||
                    isTimeInRange(checkTime, LocalTime.of(12, 0), LocalTime.of(14, 0)) ||
                    isTimeInRange(checkTime, LocalTime.of(17, 30), LocalTime.of(19, 0));
        }

        // 未知考勤类型
        return false;
    }

    /**
     * 判断时间是否在起始和结束时间之间（包含边界）
     */
    private boolean isTimeInRange(LocalTime time, LocalTime start, LocalTime end) {
        return !time.isBefore(start) && !time.isAfter(end);
    }

    /**
     * 新增打卡记录
     *
     * @param sysAttendance 打卡记录
     * @return 结果
     */
    @Override
    public AjaxResult insertSysAttendance(SysAttendance sysAttendance) {
        sysAttendance.setCreateTime(DateUtils.getNowDate());
        sysAttendance.setAttendanceDate(DateUtils.getNowDate());
        sysAttendance.setUserId(SecurityUtils.getUserId());

        String attendanceType = sysAttendance.getAttendanceType();
        Date attendanceTime = sysAttendance.getAttendanceTime();

        //校验今天是否能打卡
        Date currentDate = DateUtil.beginOfDay(DateUtil.date());
        if ("office".equals(attendanceType)) {
            SysHoliday sysHoliday = new SysHoliday();
            sysHoliday.setHolidayDate(currentDate);
            List<SysHoliday> sysHolidays = sysHolidayMapper.selectSysHolidayList(sysHoliday);
            if (CollUtil.isNotEmpty(sysHolidays)) {
                return AjaxResult.error("节假日无需打卡!");
            }

            int dayOfWeek = DateUtil.dayOfWeek(currentDate);
            if (dayOfWeek == 1 || dayOfWeek == 7) {
                return AjaxResult.error("周末无需打卡!");
            }

        } else if ("field".equals(attendanceType)) {


            Date firstDayOfMonth = DateUtil.beginOfMonth(DateUtil.date());
            Date lastDayOfMonth = DateUtil.endOfMonth(DateUtil.date());

            Map<String, Object> params = new HashMap<>();
            params.put("userId", SecurityUtils.getUserId());
            params.put("startDate", firstDayOfMonth);
            params.put("endDate", lastDayOfMonth);
            params.put("attendanceType", "field");
            List<SysAttendance> sysAttendanceList = sysAttendanceMapper.selectByParam(params);

            long attendanceCount = sysAttendanceList.stream().map(SysAttendance::getAttendanceDate).distinct().count();


            YearMonth yearMonth = YearMonth.now();
            // 获取这个月有多少天
            int daysInMonth = yearMonth.lengthOfMonth();

            if (daysInMonth - attendanceCount <= 4) {
                return AjaxResult.error("您已超过外勤打卡规定的当前月最大天数上限");
            }

        }


        // 1.验证打卡时间是否在有效范围内
        boolean isTimeValid = validateAttendanceTime(attendanceTime, attendanceType);
        if (!isTimeValid) {
            return AjaxResult.error("不在打卡时间范围");
        }


        // 2.查询今日打卡记录
        SysAttendance querySysAttendance = new SysAttendance();
        querySysAttendance.setAttendanceDate(currentDate);
        querySysAttendance.setUserId(SecurityUtils.getUserId());
        List<SysAttendance> sysAttendanceList = sysAttendanceMapper.selectSysAttendanceList(querySysAttendance);


        if (CollUtil.isNotEmpty(sysAttendanceList)) {
            String oldAttendanceType = sysAttendanceList.get(0).getAttendanceType();

            if (!attendanceType.equals(oldAttendanceType)) {
                return AjaxResult.error("当日打卡记录已存在,无法更换打卡方式");
            }

        }


        // 3.获取当前打卡时间所属的时间段
        String attendanceTimeStr = DateUtil.format(attendanceTime, "HH:mm");
        List<Map<String, Object>> timeRanges = "office".equals(attendanceType) ?
                OFFICE_TIME_RANGES : FIELD_TIME_RANGES;
        for (Map<String, Object> timeRange : timeRanges) {
            timeRange.remove("attendanceTime"); // 移除可能存在的打卡时间
            timeRange.put("isCurrent", false);  // 重置为非当前状态
        }


        String currentTimeRange = null;


        for (Map<String, Object> timeRange : timeRanges) {
            String startTime = (String) timeRange.get("startTime");
            String endTime = (String) timeRange.get("endTime");

            if ("24:00".equals(endTime)) {
                endTime = "23:59";
            }

            if (isTimeBetween(attendanceTimeStr, startTime, endTime)) {
                currentTimeRange = (String) timeRange.get("timeRange");
                break;
            }
        }

        // 4.检查该时间段是否已有打卡记录
        if (CollUtil.isNotEmpty(sysAttendanceList)) {
            // 检查是否在同一时间段已有打卡
            for (SysAttendance existing : sysAttendanceList) {
                String existingTimeStr = DateUtil.format(existing.getAttendanceTime(), "HH:mm");

                for (Map<String, Object> timeRange : timeRanges) {
                    String startTime = (String) timeRange.get("startTime");
                    String endTime = (String) timeRange.get("endTime");
                    String timeRangeStr = (String) timeRange.get("timeRange");

                    if ("24:00".equals(endTime)) {
                        endTime = "23:59";
                    }

                    // 判断现有记录和当前记录是否在同一时间段
                    boolean existingInRange = isTimeBetween(existingTimeStr, startTime, endTime);
                    boolean currentInRange = isTimeBetween(attendanceTimeStr, startTime, endTime);

                    if (existingInRange && currentInRange) {
                        return AjaxResult.error("在" + timeRangeStr + "时间段内已打卡，不能重复打卡");
                    }
                }
            }

            // 5.检查是否已完成当天所有打卡
            if ("field".equals(attendanceType) && sysAttendanceList.size() == 2) {
                return AjaxResult.error("今日已经完成所有打卡");
            } else if ("office".equals(attendanceType) && sysAttendanceList.size() == 3) {
                return AjaxResult.error("今日已经完成所有打卡");
            }
        }

        try {
            Map<String, Object> watermarkText = new HashMap<>();

            //1.获取员工姓名
            SysUser user = sysUserMapper.selectUserById(SecurityUtils.getUserId());
            String nickName = user.getNickName();
            watermarkText.put("nickName", nickName);

            //2.部门
            SysDept sysDept = sysDeptMapper.selectDeptById(SecurityUtils.getLoginUser().getDeptId());
            String deptName = sysDept.getDeptName();
            watermarkText.put("deptName", deptName);

            //打卡时间
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String createTime = simpleDateFormat.format(attendanceTime);
            watermarkText.put("createTime", createTime);

            if ("field".equals(attendanceType)) {
                watermarkText.put("attendanceType", "外勤打卡");
            } else if ("office".equals(attendanceType)) {
                watermarkText.put("attendanceType", "内勤打卡");
            }

            MultipartFile file = ImageWatermarkUtil.addWatermarkAndConvertToMultipartFile(baseUrl + sysAttendance.getAttendanceImageUrl(),
                    watermarkText);

            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.upload(filePath, file);
            sysAttendance.setAttendanceImageUrl(fileName);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        if (StrUtil.isBlank(sysAttendance.getAttendanceImageUrl())) {
            return AjaxResult.error("请拍照上传完成打卡");
        }


        // 6.执行打卡插入
        sysAttendanceMapper.insertSysAttendance(sysAttendance);
        return AjaxResult.success();
    }


    @Override
    public AjaxResult showRecord(SysAttendance sysAttendance) {

        String attendanceType = sysAttendance.getAttendanceType();


        List<Map<String, Object>> timeRangList = new ArrayList<>();
        if ("office".equals(attendanceType)) {
            timeRangList = new ArrayList<>(OFFICE_TIME_RANGES);
        } else if ("field".equals(attendanceType)) {
            timeRangList = new ArrayList<>(FIELD_TIME_RANGES);
        }

        for (Map<String, Object> timeRange : timeRangList) {
            timeRange.remove("attendanceTime"); // 移除可能存在的打卡时间
            timeRange.put("isCurrent", false);  // 重置为非当前状态
        }


        //1.查询今日打卡记录
        Date currentDate = DateUtil.beginOfDay(DateUtil.date());
        SysAttendance querySysAttendance = new SysAttendance();
        querySysAttendance.setAttendanceDate(currentDate);
        querySysAttendance.setUserId(SecurityUtils.getUserId());

        List<SysAttendance> sysAttendanceList = sysAttendanceMapper.selectSysAttendanceList(querySysAttendance);

        if (CollUtil.isNotEmpty(sysAttendanceList)) {
            // 遍历所有打卡记录
            for (SysAttendance attendance : sysAttendanceList) {
                // 获取打卡时间（仅保留时分部分用于比较）
                Date attendanceTime = attendance.getAttendanceTime();
                String attendanceTimeStr = DateUtil.format(attendanceTime, "HH:mm");

                // 遍历时间范围列表，判断打卡时间属于哪个范围
                for (Map<String, Object> timeRange : timeRangList) {
                    String startTime = (String) timeRange.get("startTime");
                    String endTime = (String) timeRange.get("endTime");

                    // 特殊处理24:00的情况
                    if ("24:00".equals(endTime)) {
                        endTime = "23:59";
                    }

                    // 比较打卡时间是否在当前时间范围内
                    boolean isBetween = isTimeBetween(attendanceTimeStr, startTime, endTime);
                    if (isBetween) {
                        timeRange.put("attendanceTime", DateUtils.parseDateToStr("YYYY-MM-dd HH:mm:ss", attendanceTime));
                        timeRange.put("isCurrent", true);
                        break;
                    }
                }
            }
        }


        return AjaxResult.success(timeRangList);
    }


    /**
     * 判断目标时间是否在起始时间和结束时间之间
     *
     * @param targetTime 目标时间（格式：HH:mm）
     * @param startTime  起始时间（格式：HH:mm）
     * @param endTime    结束时间（格式：HH:mm）
     * @return 是否在范围内
     */
    private boolean isTimeBetween(String targetTime, String startTime, String endTime) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
            Date target = sdf.parse(targetTime);
            Date start = sdf.parse(startTime);
            Date end = sdf.parse(endTime);

            // 如果结束时间小于起始时间，说明跨天（这里实际不会出现，仅做安全处理）
            if (end.before(start)) {
                return target.after(start) || target.before(end);
            }

            return target.after(start) && target.before(end);
        } catch (ParseException e) {
            return false;
        }
    }


    @Override
    public void expertTable(HttpServletResponse response, SysAttendance sysAttendance) {


        List<SysAttendance> sysAttendanceList = selectSysAttendanceList(sysAttendance);


        System.out.println(sysAttendanceList);


    }
}
